package retrofit.boot.autoconfigure;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
import retrofit.Endpoint;
import retrofit.ErrorHandler;
import retrofit.RequestInterceptor;
import retrofit.RestAdapter;
import retrofit.boot.annotation.AliasHelper;
import retrofit.boot.client.*;
import retrofit.boot.autoconfigure.RetrofitClientProperties.RetrofitClientConfiguration;
import retrofit.boot.converter.FastjsonConverter;
import retrofit.boot.util.RetrofitUtils;
import retrofit.converter.Converter;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by wulg on 2019/11/5
 * description:
 */
public final class RetrofitContext implements ApplicationContextAware {

    private RetrofitClientConfiguration defaultConfig;

    private Map<String, RetrofitClientConfiguration> configs = new ConcurrentHashMap<>();

    private final RetrofitClientProperties properties;

    private ApplicationContext applicationContext;

    private Map<String,RestAdapter.Builder>  builderMap = new ConcurrentHashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public RetrofitContext(RetrofitClientProperties properties) {
        this.properties = properties;
        String defaultConfigName = properties.getDefaultConfig();
        Map<String, RetrofitClientConfiguration> oldConfigs = properties.getConfig();
        if(oldConfigs.containsKey(defaultConfigName)){
            defaultConfig = buildConfig(oldConfigs.get(defaultConfigName));
            oldConfigs.remove(defaultConfigName);
        }else{
            defaultConfig = buildConfig(null);
        }
        if(MapUtils.isNotEmpty(oldConfigs)){
            for(Map.Entry<String, RetrofitClientConfiguration> entry : oldConfigs.entrySet()){
                configs.put(entry.getKey(),buildConfig(entry.getValue()));
            }
        }
    }

    private RetrofitClientConfiguration buildConfig(RetrofitClientConfiguration config){
        if(config == null){
            RetrofitClientConfiguration configuration = new RetrofitClientConfiguration();
            configuration.setLogLevel(RestAdapter.LogLevel.NONE);
            configuration.setErrorHandler(RetrofitErrorHandler.class);
            configuration.setRequestInterceptor(RetrofitRequestInterceptor.class);
            configuration.setConverter(FastjsonConverter.class);
            return configuration;
        }
        if(config.getTimeout() == null){
            config.setTimeout(defaultConfig != null ? defaultConfig.getTimeout() : null);
        }
        if(StringUtils.isNotBlank(config.getUrl())){
            config.setUrl(RetrofitUtils.rebuildUrl(config.getUrl()));
        }else{
            config.setUrl(defaultConfig != null ? defaultConfig.getUrl(): null);
        }
        if(config.getLogLevel() == null){
            config.setLogLevel(defaultConfig != null ? defaultConfig.getLogLevel(): RestAdapter.LogLevel.NONE);
        }
        if(config.getErrorHandler() == null){
            config.setErrorHandler(defaultConfig != null ? defaultConfig.getErrorHandler() : RetrofitErrorHandler.class);
        }
        if(config.getRequestInterceptor() == null){
            config.setRequestInterceptor(defaultConfig != null ? defaultConfig.getRequestInterceptor() : RetrofitRequestInterceptor.class);
        }
        if(config.getConverter() == null){
            config.setConverter(defaultConfig != null ? defaultConfig.getConverter() : FastjsonConverter.class);
        }
        return config;
    }

    public Endpoint getEndpoint(String name){
        String endpointAlias = AliasHelper.getEndpointAlias(name);
        Assert.isTrue(applicationContext.containsBean(endpointAlias), "The endpoint bean is not registered! name="+name);
        return (Endpoint)applicationContext.getBean(endpointAlias);
    }

    public RetrofitClientConfiguration getClientConfig(String name){
        return ObjectUtils.defaultIfNull(configs.get(name),defaultConfig);
    }

    public RestAdapter.Builder getRetrofitClientBuilder(String name){
        if(!builderMap.containsKey(name)){
            RetrofitClientConfiguration config = this.getClientConfig(name);
            IRetrofitClient retrofitClient = applicationContext.getBean(IRetrofitClient.class);
            RestAdapter.Builder builder = new RestAdapter.Builder();
            ErrorHandler errorHandler = applicationContext.getBean(config.getErrorHandler());
            RequestInterceptor requestInterceptor = applicationContext.getBean(config.getRequestInterceptor());
            Converter converter = applicationContext.getBean(config.getConverter());
            builder.setClient(new RetrofitSmartClient(retrofitClient,
                    RequestWrapper.Options.builder()
                            .endpointName(name)
                            .timeout(config.getTimeout())
                            .build()))
                    .setErrorHandler(errorHandler)
                    .setRequestInterceptor(requestInterceptor)
                    .setConverter(converter)
                    .setLogLevel(config.getLogLevel());
            builderMap.put(name,builder);
        }
        return builderMap.get(name);
    }
}
